/**
 * 同時に8接続まで出来るtelnetサーバ。
 * 23番ポートでListenして、受信データをエコーバックします。
 */
#include "boot/sketch.h"
#include "NyLPC_uipService.h"
//イーサネット用の初期化情報
const struct NyLPC_TEthAddr ethaddr=NyLPC_TEthAddr_pack(0x00,0x01,0x02,0x03,0x04,0x05);
const struct NyLPC_TIPv4Addr ipaddr=NyLPC_TIPv4Addr_pack(192,168,128,201);
const struct NyLPC_TIPv4Addr netmask=NyLPC_TIPv4Addr_pack(255,255,255,0);
const struct NyLPC_TIPv4Addr gateway=NyLPC_TIPv4Addr_pack(192,168,128,254);



#define NUM_OF_TH 8
struct TProc{
	NyLPC_TcThread_t th;
	NyLPC_TcTcpSocket_t socket;
	char rbuf[512];
}proc[NUM_OF_TH];


void setup(void)
{
	int i;
	//UipServiceの初期化
	NyLPC_cUipService_initialize();
	//TCPスレッドの準備
	for(i=0;i<NUM_OF_TH;i++){
		NyLPC_cThread_initialize(&(proc[i].th),160);
		NyLPC_cTcpSocket_initialize(&(proc[i].socket),proc[i].rbuf,512);
	}
}

/**
 * サーバプロセス。
 * 接続済のソケットを処理します。
 */
int server(void* p)
{
	struct TProc* proc=(struct TProc*)p;
	NyLPC_TInt32 s;
	const char* buf;
	const char* src;
	NyLPC_TInt16 sent;


	if(!NyLPC_cTcpSocket_accept(&(proc->socket),3000)){
		return -1;
	}
	//接続中は送信する。
	s=NyLPC_cTcpSocket_precv(&(proc->socket),(const void**)&buf,1000);
	while(s>=0){
		if(s>0){
			//受信した内容をそのまま送信。
			src=buf;
			while(s>0){
				sent=NyLPC_cTcpSocket_send(&(proc->socket),src,s,30000);
				if(sent<=0){
					NyLPC_cTcpSocket_close(&(proc->socket),10000);
					return -1;
				}
				//読み出し位置を調整
				src+=sent;
				s-=sent;
				NyLPC_cTcpSocket_pseek(&(proc->socket),sent);
			}
		}
		s=NyLPC_cTcpSocket_precv(&(proc->socket),(const void**)&buf,1000);
	}
	NyLPC_cTcpSocket_close(&(proc->socket),10000);
	return 1;
}



void loop(void)
{
	NyLPC_TcIPv4Config_t config;
	NyLPC_TcTcpListener_t listener;
	int i;


	NyLPC_cIPv4Config_initialzeForEthernet(&config,&ethaddr,1480);
	NyLPC_cIPv4Config_setDefaultRoute(&config,&gateway);
	NyLPC_cIPv4Config_setIp(&config,&ipaddr,&netmask);


	NyLPC_cTcpListener_initialize(&listener,23);
	NyLPC_cUipService_start(&config);
	for(;;){
		//ターミネイト状態のタスクを検索
		for(i=0;i<NUM_OF_TH;i++){
			if(NyLPC_cThread_isTerminated(&(proc[i].th))){
				//リスニング
				if(!NyLPC_cTcpListener_listen(&listener,&(proc[i].socket),10000)){
					continue;
				}
				//タスク起動
				NyLPC_cThread_start(&(proc[i].th),server,&(proc[i]));
			}
		}
	}
	for(;;){}
}
